package com.dji.sample.manage.scheduled;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dji.sample.common.util.DistanceUtil;
import com.dji.sample.manage.dao.DevicePlayLineInfoMapper;
import com.dji.sample.manage.dao.DevicePositionMapper;
import com.dji.sample.manage.dao.StatisticsDayRecordMapper;
import com.dji.sample.manage.dao.StatisticsDayRecordOneMapper;
import com.dji.sample.manage.model.entity.DevicePlayLineEntity;
import com.dji.sample.manage.model.entity.DevicePositionEntity;
import com.dji.sample.manage.model.entity.StatisticsDayRecordEntity;
import com.dji.sample.manage.model.entity.StatisticsDayRecordOneEntity;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.select.Select;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author yjt
 * @date 2022-11-09
 * @description:
 */
@Component
@EnableScheduling
@AllArgsConstructor
@Slf4j
public class Statisticsjob {
    private final ExecutorService scheduledExecutorService = new ThreadPoolExecutor(4, 4,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(10000), new ThreadFactoryImpl("statisticsjob"));

    final DevicePlayLineInfoMapper devicePlayLineInfoMapper;

    final DevicePositionMapper devicePositionMapper;

    final StatisticsDayRecordMapper statisticsDayRecordMapper;
    final StatisticsDayRecordOneMapper statisticsDayRecordOneMapper;
    RedisTemplate<String, Object> redisTemplate;

    private static final Integer INIT_DAY = 90;

//    @Scheduled(cron = "0 0 1 * * ? ")
     @Scheduled(cron = "0 0 */3 * * ?")
    public void run() {
        Boolean success = redisTemplate.opsForValue().setIfAbsent("djcloud:statisticsjob", "1", 5L, TimeUnit.MINUTES);
                if(!Boolean.TRUE.equals(success)){
            return;
        }
        LocalDate localDate = LocalDate.now();
        String time = localDate.plusDays(-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        //String time = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        statisticsDayRecordMapper.delete(new LambdaUpdateWrapper<StatisticsDayRecordEntity>().eq(StatisticsDayRecordEntity::getDate, time));
        statisticsFly(time);
        statisticsFlyType(time);
    }

    @PostConstruct
    public void init() {
        if (statisticsDayRecordMapper.selectCount(new LambdaQueryWrapper<StatisticsDayRecordEntity>().last(" limit 1")) == 0) {
            LocalDate localDate = LocalDate.now();
            for (int i = 1; i <= INIT_DAY; i++) {
                String time = localDate.plusDays(-i).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                statisticsDayRecordMapper.delete(new LambdaUpdateWrapper<StatisticsDayRecordEntity>().eq(StatisticsDayRecordEntity::getDate, time));
                statisticsFly(time);
            }
        }
    }
    private void statisticsFlyType(String time) {
        List<DevicePlayLineEntity> list = devicePlayLineInfoMapper.selectList(new LambdaQueryWrapper<DevicePlayLineEntity>().likeRight(DevicePlayLineEntity::getCreateTime, time).isNotNull(DevicePlayLineEntity::getEndPositionId).isNotNull(DevicePlayLineEntity::getStartPositionId));
        List<DevicePlayLineEntity> type1List = new ArrayList<>();
        List<DevicePlayLineEntity> type2List = new ArrayList<>();
        List<DevicePlayLineEntity> type3List = new ArrayList<>();
        for (DevicePlayLineEntity entity : list) {
            switch (entity.getType()) {
                case "1":
                    type1List.add(entity);
                    break;
                case "2":
                    type2List.add(entity);
                    break;
                case "3":
                    type3List.add(entity);
                    break;
                default:
                    // Handle other types if necessary
                    break;
            }
        }
        //List<DevicePlayLineEntity> devicePlayLineEntities = devicePlayLineInfoMapper.selectList(new LambdaQueryWrapper<DevicePlayLineEntity>().likeRight(DevicePlayLineEntity::getCreateTime, time).isNotNull(DevicePlayLineEntity::getEndPositionId).isNotNull(DevicePlayLineEntity::getStartPositionId));
        double flyTime = 0, distance = 0 , count = 0;String orgCode =null,deviceSn =null,type=null; Long orgId = null;
        double flyTimeTwo = 0, distanceTwo = 0 , countTwo = 0;String orgCodeTwo =null,deviceSnTwo =null,typeTwo=null; Long orgIdTwo = null;
        double flyTimeThree = 0, distanceThree = 0 , countThree = 0;String orgCodeThree =null,deviceSnThree =null,typeThree=null; Long orgIdThree = null;

        if(type1List.size() > 0){
            List<StatisticsDayRecordOneEntity> statisticsDayRecordOneEntities = statisticsDayRecordOneMapper.selectList(new LambdaQueryWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "1"));
            if(statisticsDayRecordOneEntities.size() > 0){
                statisticsDayRecordOneMapper.delete(new LambdaUpdateWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "1"));
            }
            for (DevicePlayLineEntity devicePlayLineEntity : type1List) {
                distance=getDistance(devicePlayLineEntity);
                flyTime = getTime(devicePlayLineEntity);
                orgCode = devicePlayLineEntity.getOrgCode();
                orgId = devicePlayLineEntity.getOrgId();
                type = devicePlayLineEntity.getType();
                deviceSn = devicePlayLineEntity.getDeviceSn();
                count =1;
                insertRecordOne(time,  count, flyTime, distance,orgCode, orgId,deviceSn,type);
            }

          }



      if(type2List.size() > 0) {
          List<StatisticsDayRecordOneEntity> statisticsDayRecordOneEntities = statisticsDayRecordOneMapper.selectList(new LambdaQueryWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "1"));
          if(statisticsDayRecordOneEntities.size() > 0){
              statisticsDayRecordOneMapper.delete(new LambdaUpdateWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "2"));
          }
        for (DevicePlayLineEntity devicePlayLineEntity : type2List) {
            flyTimeTwo = getTime(devicePlayLineEntity);
            distanceTwo = getDistance(devicePlayLineEntity);
            orgCodeTwo = devicePlayLineEntity.getOrgCode();
            orgIdTwo = devicePlayLineEntity.getOrgId();
            typeTwo = devicePlayLineEntity.getType();
            deviceSnTwo = devicePlayLineEntity.getDeviceSn();
            countTwo = 1;
            insertRecordOne(time, countTwo, flyTimeTwo, distanceTwo, orgCodeTwo, orgIdTwo, deviceSnTwo, typeTwo);
        }


    }
        if(type3List.size() > 0) {
            List<StatisticsDayRecordOneEntity> statisticsDayRecordOneEntities1 = statisticsDayRecordOneMapper.selectList(new LambdaQueryWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "2"));
            if (statisticsDayRecordOneEntities1.size() > 0) {
                statisticsDayRecordOneMapper.delete(new LambdaUpdateWrapper<StatisticsDayRecordOneEntity>().eq(StatisticsDayRecordOneEntity::getDate, time).eq(StatisticsDayRecordOneEntity::getType, "2"));
            }
            for (DevicePlayLineEntity devicePlayLineEntity : type3List) {
                flyTimeThree  = getTime(devicePlayLineEntity);
                distanceThree = getDistance(devicePlayLineEntity);
                orgCodeThree = devicePlayLineEntity.getOrgCode();
                orgIdThree = devicePlayLineEntity.getOrgId();
                typeThree = devicePlayLineEntity.getType();
                deviceSnThree = devicePlayLineEntity.getDeviceSn();
                countThree = 1;
                insertRecordOne(time, countThree, flyTimeThree, distanceThree, orgCodeThree, orgIdThree, deviceSnThree, typeThree);
            }


        }
}
    private void insertRecordOne(String time, double count, double flyTime, double distance,String orgCode, Long orgId,String deviceSn,String type) {
        StatisticsDayRecordOneEntity statisticsDayRecordOneEntity = new StatisticsDayRecordOneEntity();
        statisticsDayRecordOneEntity.setDate(time);
        statisticsDayRecordOneEntity.setFlyTime(flyTime);
        statisticsDayRecordOneEntity.setFlyDistance(distance);
        statisticsDayRecordOneEntity.setFlyCount(count);
        statisticsDayRecordOneEntity.setOrgCode(orgCode);
        statisticsDayRecordOneEntity.setOrgId(orgId);
        statisticsDayRecordOneEntity.setSn(deviceSn);
        statisticsDayRecordOneEntity.setType(type);
        statisticsDayRecordOneMapper.insert(statisticsDayRecordOneEntity);
    }
    public void statisticsFly(String time) {
        List<DevicePlayLineEntity> list = devicePlayLineInfoMapper.selectList(new LambdaQueryWrapper<DevicePlayLineEntity>().likeRight(DevicePlayLineEntity::getCreateTime, time).isNotNull(DevicePlayLineEntity::getEndPositionId).isNotNull(DevicePlayLineEntity::getStartPositionId));
        if (list.isEmpty()) {
            return;
        }
        Map<Long, Item> sMap = new HashMap<>();
        double flyTime = 0, distance = 0;
        for (DevicePlayLineEntity devicePlayLineInfo : list) {
            flyTime = getTime(devicePlayLineInfo);
            distance = getDistance(devicePlayLineInfo);
            if (sMap.containsKey(devicePlayLineInfo.getOrgId())) {
                sMap.get(devicePlayLineInfo.getOrgId()).addDistance(distance).addFlyCount(1).addFlyTime(flyTime).addDeviceSn(devicePlayLineInfo.getDeviceSn());
            } else {
                sMap.put(devicePlayLineInfo.getOrgId(), new Item(devicePlayLineInfo.getOrgCode(), devicePlayLineInfo.getOrgId(), 1, flyTime, distance, time).addDeviceSn(devicePlayLineInfo.getDeviceSn()));
            }
        }
        //计算真实距离
        sMap.forEach((k, v) -> {
            scheduledExecutorService.execute(new Runnable() {
                @Override
                public void run() {
                    double total = 0;
                    for (String s : v.deviceSn.stream().distinct().collect(Collectors.toList())) {
                        List<DevicePositionEntity> lineEntities = devicePositionMapper.selectList(new LambdaQueryWrapper<DevicePositionEntity>().eq(DevicePositionEntity::getDeviceSn, s).likeRight(DevicePositionEntity::getCreateTime, time));
                        total += getDistance(lineEntities);
                    }
                    v.setFlyDistance(total);
                    statisticsDayRecordMapper.insert(v.trans());
                }
            });
        });

    }

    static class Item {
        private String orgCode;
        private Long orgId;
        private Integer flyCount;
        private double flyTime;
        private double flyDistance;
        private String date;
        private final List<String> deviceSn = new ArrayList<>();

        public Item() {
        }

        public Item(String orgCode, Long orgId, Integer flyCount, double flyTime, double flyDistance, String date) {
            this.orgCode = orgCode;
            this.orgId = orgId;
            this.flyCount = flyCount;
            this.flyTime = flyTime;
            this.flyDistance = flyDistance;
            this.date = date;
        }

        public StatisticsDayRecordEntity trans() {
            StatisticsDayRecordEntity statisticsDayRecordEntity = new StatisticsDayRecordEntity();
            statisticsDayRecordEntity.setDate(date);
            statisticsDayRecordEntity.setFlyTime(flyTime);
            statisticsDayRecordEntity.setFlyDistance(flyDistance);
            statisticsDayRecordEntity.setFlyCount(flyCount);
            statisticsDayRecordEntity.setDate(date);
            statisticsDayRecordEntity.setOrgCode(orgCode);
            statisticsDayRecordEntity.setOrgId(orgId);
            return statisticsDayRecordEntity;
        }


        public Item addDeviceSn(String deviceSn) {
            this.deviceSn.add(deviceSn);
            return this;
        }

        public Item addFlyCount(int count) {
            this.flyCount += count;
            return this;
        }

        public Item addFlyTime(double time) {
            this.flyTime += time;
            return this;
        }

        public Item addDistance(double distance) {
            this.flyDistance += distance;
            return this;
        }

        public String getDate() {
            return date;
        }

        public void setDate(String date) {
            this.date = date;
        }

        public String getOrgCode() {
            return orgCode;
        }

        public void setOrgCode(String orgCode) {
            this.orgCode = orgCode;
        }

        public Long getOrgId() {
            return orgId;
        }

        public void setOrgId(Long orgId) {
            this.orgId = orgId;
        }

        public Integer getFlyCount() {
            return flyCount;
        }

        public void setFlyCount(Integer flyCount) {
            this.flyCount = flyCount;
        }

        public double getFlyTime() {
            return flyTime;
        }

        public void setFlyTime(Integer flyTime) {
            this.flyTime = flyTime;
        }

        public double getFlyDistance() {
            return flyDistance;
        }

        public void setFlyDistance(double flyDistance) {
            this.flyDistance = flyDistance;
        }
    }

    public double getDistance(List<DevicePositionEntity> lineEntities) {
        try {
            DevicePositionEntity devicePositionEntity = null;
            double distance = 0;
            boolean first = true;
            for (DevicePositionEntity lineEntity : lineEntities) {
                if (first) {
                    devicePositionEntity = lineEntity;
                    first = false;
                    continue;
                }
                distance += DistanceUtil.getDistance(Double.parseDouble(lineEntity.getLongitude()), Double.parseDouble(lineEntity.getLatitude()), Double.parseDouble(devicePositionEntity.getLongitude()), Double.parseDouble(devicePositionEntity.getLatitude()));
                devicePositionEntity = lineEntity;
            }
            return distance;
        } catch (Exception e) {
            log.error("统计异常", e);
            return 0;
        }

    }


    public double getDistance(DevicePlayLineEntity devicePlayLineInfo) {
        if (devicePlayLineInfo.getStartPosition() == null || devicePlayLineInfo.getEndPosition() == null) {
            return 0;
        }
        String[] start = devicePlayLineInfo.getStartPosition().split(",");
        String[] end = devicePlayLineInfo.getEndPosition().split(",");
        if (start.length <= 1 || end.length <= 1) {
            return 0;
        }
        return DistanceUtil.getDistance(Double.parseDouble(start[0]), Double.parseDouble(start[1]), Double.parseDouble(end[0]), Double.parseDouble(end[1]));
    }

    public long getTime(DevicePlayLineEntity devicePlayLineInfo) {
        if (devicePlayLineInfo.getStartTime() == null || devicePlayLineInfo.getEndTime() == null) {
            return 0;
        }
        return devicePlayLineInfo.getEndTime() - devicePlayLineInfo.getStartTime();
    }
}
